/**
 * @Copyright ®2015 Sinosoft Co. Ltd. All rights reserved.<br/>
 * 项目名称 : 电子商务云服务平台
 * 创建日期 : 2016年6月28日
 * 修改历史 : 
 *     1. [2016年6月30日]修改文件 by chihouliang
 *      添加Javadoc注释，更新代码规范，静态工具类增加private构造函数，增加logger日志
 */
package com.gavinwind.inspay.common.util;

import com.gavinwind.inspay.common.exception.system.SignErrException;
import com.gavinwind.inspay.common.logger.PlatformLogger;
import org.apache.commons.codec.digest.DigestUtils;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;

/**
 * 安全加密工具，提供MD5、SHA1等加密方法
 * @Title: SecurityUtil.java 
 * @Package com.sinosoft.platform.common.util 
 * @Description: 安全加密工具，提供MD5、SHA1等加密方法
 * @author Gavin
 * @date 2015-3-20 下午5:39:58 
 * @version 1.0
 * @see DESSecurityUtil
 */
public class SecurityUtil {

    /**日志*/
    private static PlatformLogger logger = PlatformLogger.getLogger(SecurityUtil.class);

    /*
     * 安全加密工具不允许创建对象
     */
    private SecurityUtil() {}

    /**
     * 根据key生成MD5加密信息，编码使用UTF-8。MD5加密是不可逆的，一般使用MD5加密是为了验证数据的正确性，防止数据在传输过程中被篡改。在对数据与key值进行拼接时，key值在前（开发者只需调用相关方法，无需关心）。
     * @param cRequestMessage 需要加密的原始数据
     * @param cKey 约定好的key值
     * @return MD5加密后字符串
     * @throws Exception
     */
    public static String signMD5(String cRequestMessage, String cKey) throws Exception {
        // 数字签名校验
        String tSource = cKey + cRequestMessage;
        return DigestUtils.md5Hex(tSource.getBytes("UTF-8"));
    }

    /**
     * 对原始数据进行MD5加密，编码使用UTF-8，MD5加密不可逆。
     * @param cPlainText 需要加密的原始数据
     * @return MD5加密后的字符串
     */
    public static String Md5(String cPlainText) {
        StringBuffer tBuf = new StringBuffer();
        try {
            MessageDigest tMd = MessageDigest.getInstance("MD5");
            tMd.update(cPlainText.getBytes("utf-8"));
            byte[] tByte = tMd.digest();
            int i;
            for (int j = 0; j < tByte.length; j++) {
                i = tByte[j];
                if (i < 0) {
                    i += 256;
                }
                if (i < 16) {
                    tBuf.append("0");
                }
                tBuf.append(Integer.toHexString(i));
            }
        } catch (Exception e) {
            logger.error("SecurityUtil系统异常:",e);
        }
        return tBuf.toString();
    }

    /**
     * 对数据进行SHA1加密，编码使用UTF-8，SHA1加密不可逆。
     * @param cDecript 需要加密字符串
     * @return SHA1加密后字符串
     * @history 
     *   1.edit by chihouliang 2016-7-1 增加Logger日志
     */
    public static String SHA1(String cDecript) {
        StringBuffer tHexString = new StringBuffer();
        try {
            MessageDigest tDigest = MessageDigest.getInstance("SHA-1");
            tDigest.update(cDecript.getBytes());
            byte[] tMessageDigest = tDigest.digest();
            // Create Hex String
            // 字节数组转换为 十六进制 数
            for (int i = 0; i < tMessageDigest.length; i++) {
                String tShaHex = Integer.toHexString(tMessageDigest[i] & 0xFF);
                if (tShaHex.length() < 2) {
                    tHexString.append(0);
                }
                tHexString.append(tShaHex);
            }

        } catch (NoSuchAlgorithmException e) {
            logger.error("SecurityUtil系统异常:",e);
        }
        return tHexString.toString();
    }

    /**
     * 对数据进行des加密，des加密后数据时可以还原出原始数据的。解密使用decryptDES方法
     * @param cMsg 需要进行DES加密原始数据（明文数据）
     * @return DES加密后的密文
     * @history 
     *      1.add by chenxin   2016-1-18 13:25
     *      2.edit by chihouliang 2016-7-1 增加异常处理，Logger日志
     */
    public static String encryptDES(String cMsg) throws SignErrException {
        DESSecurityUtil tDesUtil;
        String tResult = "";
        try {
            tDesUtil = new DESSecurityUtil();
            tResult = tDesUtil.encrypt(cMsg);
        } catch (Exception e) {
            logger.error("SecurityUtil系统异常:",e);
            throw new SignErrException(e.getMessage());
        }
        return tResult;
    }

    /**
     * 对数据使用des加密后的密文进行解密。 对应加密方法encryptDES 
     * @history 
     *  1.add by chenxin   2016-1-18 13:25
     * @param cMsg 使用des加密后的密文数据（密文数据）
     * @return 解密后的明文数据
     * @history 
     *   1.edit by chihouliang 2016-7-1 增加Logger日志
     */
    public static String decryptDES(String cMsg) throws SignErrException {
        DESSecurityUtil tDesUtil;
        String tResult = "";
        try {
            tDesUtil = new DESSecurityUtil();
            tResult = tDesUtil.decrypt(cMsg);
        } catch (Exception e) {
            logger.error("SecurityUtil系统异常:",e);
            throw new SignErrException(e.getMessage());
        }
        return tResult;
    }

    /**
     * AES加密
     * @param content 待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的byte[]
     * @throws Exception
     */
    public static byte[] aesEncryptToBytes(String content, String encryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(encryptKey.getBytes());
        kgen.init(128, random);

        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));

        return cipher.doFinal(content.getBytes("utf-8"));
    }

    /**
     * AES加密为base 64 code
     * @param content 待加密的内容
     * @param encryptKey 加密密钥
     * @return 加密后的base 64 code
     * @throws Exception
     */
    public static String aesEncrypt(String content, String encryptKey) throws Exception {
        return base64Encode(aesEncryptToBytes(content, encryptKey));
    }

    /**
     * AES解密
     * @param encryptBytes 待解密的byte[]
     * @param decryptKey 解密密钥
     * @return 解密后的String
     * @throws Exception
     */
    public static String aesDecryptByBytes(byte[] encryptBytes, String decryptKey) throws Exception {
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(decryptKey.getBytes());
        kgen.init(128, random);
        Cipher cipher = Cipher.getInstance("AES");
        cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(kgen.generateKey().getEncoded(), "AES"));
        byte[] decryptBytes = cipher.doFinal(encryptBytes);

        return new String(decryptBytes);
    }

    /**
     * 将base 64 code AES解密
     * @param encryptStr 待解密的base 64 code
     * @param decryptKey 解密密钥
     * @return 解密后的string
     * @throws Exception
     */
    public static String aesDecrypt(String encryptStr, String decryptKey) throws Exception {
        return StringUtil.isEmpty(encryptStr) ? null : aesDecryptByBytes(base64Decode(encryptStr), decryptKey);
    }

    /**
     * base 64 encode
     * @param bytes 待编码的byte[]
     * @return 编码后的base 64 code
     */
    public static String base64Encode(byte[] bytes){
        return new BASE64Encoder().encode(bytes);
    }

    /**
     * base 64 decode
     * @param base64Code 待解码的base 64 code
     * @return 解码后的byte[]
     * @throws Exception
     */
    public static byte[] base64Decode(String base64Code) throws Exception{
        return StringUtil.isEmpty(base64Code) ? null : new BASE64Decoder().decodeBuffer(base64Code);
    }

    public static String generateAESKey(String key) throws Exception{
        KeyGenerator kgen = KeyGenerator.getInstance("AES");
        SecureRandom random= SecureRandom.getInstance("SHA1PRNG");
        random.setSeed(key.getBytes());
        kgen.init(128,random);
        SecretKey secretKey=kgen.generateKey();
        byte[]enCodeFormat=secretKey.getEncoded();
        BASE64Encoder coder=new BASE64Encoder();
        return coder.encode(enCodeFormat);
    }

    public static void main(String[] args) throws Exception {

        String content = "我爱你";
        System.out.println("加密前：" + content);

        String key = "123456";
        System.out.println("加密密钥和解密密钥：" + key);

        String encrypt = aesEncrypt(content, key);
        System.out.println("加密后：" + encrypt);

        String decrypt = aesDecrypt(encrypt, key);
        System.out.println("解密后：" + decrypt);

        String zmKey = generateAESKey("123456");
        System.out.println("加密后的key：" + zmKey);

    }

}